package com.dlc.shop.service.impl;


import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.PhoneUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.dlc.shop.bean.app.dto.OrderSelfStationDto;
import com.dlc.shop.bean.app.dto.StationSalesDto;
import com.dlc.shop.bean.dto.*;
import com.dlc.shop.bean.enums.*;
import com.dlc.shop.bean.event.SeckillOrderStockEvent;
import com.dlc.shop.bean.model.*;
import com.dlc.shop.bean.param.OfflineHandleEventAuditParam;
import com.dlc.shop.bean.param.StationDetailParam;
import com.dlc.shop.bean.vo.SkuStockVO;
import com.dlc.shop.bean.vo.StockPointSkuVO;
import com.dlc.shop.bean.vo.UserDeliveryInfoVO;
import com.dlc.shop.bean.vo.WarehouseVO;
import com.dlc.shop.common.config.Constant;
import com.dlc.shop.common.constants.AllotOrderStatusEnum;
import com.dlc.shop.common.constants.SegmentIdKey;
import com.dlc.shop.common.enums.StationStockStatus;
import com.dlc.shop.common.enums.StatusEnum;
import com.dlc.shop.common.enums.SysTypeEnum;
import com.dlc.shop.common.exception.YamiShopBindException;
import com.dlc.shop.common.util.Arith;
import com.dlc.shop.common.util.PageParam;
import com.dlc.shop.common.util.PrincipalUtil;
import com.dlc.shop.dao.StationMapper;
import com.dlc.shop.service.*;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 自提点
 *
 * @author YXF
 * @date 2020-04-23 15:18:29
 */
@Service
@RequiredArgsConstructor
public class StationServiceImpl extends ServiceImpl<StationMapper, Station> implements StationService {

    private final StationMapper stationMapper;
    private final AllotOrderService allotOrderService;
    private final PurchaseOrderService purchaseOrderService;
    private final TakeStockService takeStockService;
    private final OfflineHandleEventService offlineHandleEventService;
    private final SegmentService segmentService;
    private final SkuStockService skuStockService;
    private final ApplicationEventPublisher eventPublisher;
    @Lazy
    private final WarehouseService warehouseService;
    private final StockPointSkuService stockPointSkuService;
    private final int TEN = 10;
    private final int TWELVE = 12;
    private final int EIGHTEEN = 18;
    private final int THIRTY = 30;

    @Override
    public IPage<Station> getPage(PageParam<Station> page, Station station) {
        IPage<Station> mapperPage = stationMapper.getPage(page, station);
        for (Station record : mapperPage.getRecords()) {
            if (PrincipalUtil.isMobile(record.getPhone())){
                record.setPhone(PhoneUtil.hideBetween(record.getPhone()).toString());
            }
        }
        if (mapperPage.getRecords().size() == 0) {
            return mapperPage;
        }
        if (Objects.nonNull(station.getSkuId())) {
            List<Long> stationIds = mapperPage.getRecords().stream().map(Station::getStationId).collect(Collectors.toList());
            Map<Long, Integer> stockMap = skuStockService.getStockMapBySkuIdAndStockPointIds(station.getSkuId(), stationIds);
            for (Station s : mapperPage.getRecords()) {
                s.setStock(stockMap.containsKey(s.getStationId()) ? stockMap.get(s.getStationId()) : 0);
            }
        }
        return mapperPage;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void auditApply(Long eventId, Long handleId, String reapplyReason) {
        // 更新活动为待审核状态
        stationMapper.updateStatus(handleId, StationEnum.WAIT_AUDIT.getValue());

        // 更新事件状态
        offlineHandleEventService.updateToApply(eventId, reapplyReason);
    }

    @Override
    public IPage<StationDetailParam> getStationList(PageParam page, OrderStationDto orderStationDTO, String userId) {
        // 要判断门店是否有库存，所以先查询所有的门店列表
        List<Station> shopStationList = stationMapper.listSimpleStation(orderStationDTO.getShopId(), StatusEnum.ENABLE.value());
        // 没有门店，直接返回null
        if (CollUtil.isEmpty(shopStationList)) {
            IPage<StationDetailParam> pageVO = new PageParam<>();
            pageVO.setTotal(0L);
            pageVO.setPages(0);
            return pageVO;
        }

        // 有库存，可以自提的门店id列表
        Set<Long> stationSet = stationStockSet(orderStationDTO.getStationProdList(), shopStationList, orderStationDTO, null);
        // 查询门店列表及计算距离
        IPage<StationDetailParam> stationDetailParamIpage = stationMapper.getStationList(page,orderStationDTO);
        // 拆分处理门店列表的数据
        handleStationOrderInfo(stationSet, stationDetailParamIpage.getRecords());
        return stationDetailParamIpage;
    }

    private Set<Long> stationStockSet(List<OrderStationProdDto> orderStationSpuList, List<Station> stations, OrderStationDto orderStationDTO, Long defaultStockPointId) {
        // 库存模式是共享总部库存， 或者包含虚拟商品，需要查询默认库存
        if (Objects.isNull(defaultStockPointId)) {
            List<WarehouseVO> warehousedList = warehouseService.listWarehouseByShopId(orderStationDTO.getShopId(), SysTypeEnum.MULTISHOP.value());
            defaultStockPointId = warehousedList.get(0).getWarehouseId();
        }
        List<StockPointSkuVO> stockPointSkuVOList = new ArrayList<>(orderStationSpuList.size() * stations.size());
        for (OrderStationProdDto orderStationProdDTO : orderStationSpuList) {
            // 商品类别是虚拟商品，使用默认库存
            if (Objects.equals(orderStationProdDTO.getSpuMold(), ProdMoldEnum.VIRTUAL.value())) {
                stockPointSkuVOList.add(new StockPointSkuVO(orderStationProdDTO.getSkuId(), defaultStockPointId));
                continue;
            }
            Map<Long, StockPointSkuDTO> stockPointMap = Collections.emptyMap();
            if (CollUtil.isNotEmpty(orderStationProdDTO.getStockPointList())) {
                stockPointMap = orderStationProdDTO.getStockPointList().stream()
                        .collect(Collectors.toMap(StockPointSkuDTO::getStockPointId, Function.identity()));
            }
            for (Station station : stations) {
                int stockMode = station.getStockMode();
                if (stockPointMap.containsKey(station.getStationId())) {
                    StockPointSkuDTO stockPointSku = stockPointMap.get(station.getStationId());
                    stockMode = stockPointSku.getStockMode();
                }
                if (Objects.equals(stockMode, StockModeEnum.ALL_STOCK.value())) {
                    stockPointSkuVOList.add(new StockPointSkuVO(orderStationProdDTO.getSkuId(), defaultStockPointId));
                } else {
                    stockPointSkuVOList.add(new StockPointSkuVO(orderStationProdDTO.getSkuId(), station.getStationId()));
                }
            }
        }
        Map<String, SkuStockVO> stockMap;
        if (Objects.isNull(orderStationDTO.getSeckillId())) {
            // 非秒杀订单
            stockMap = skuStockService.mapSkuPointStockByStockPoints(stockPointSkuVOList);
        } else {
            // 秒杀订单
            SeckillOrderStockEvent seckillOrderStockEvent = new SeckillOrderStockEvent(orderStationDTO.getSeckillId(), stockPointSkuVOList);
            eventPublisher.publishEvent(seckillOrderStockEvent);
            Map<String, Integer> seckillStockMap = seckillOrderStockEvent.getStockMap();
            stockMap = new HashMap<>(seckillStockMap.size());
            for (Map.Entry<String, Integer> entry : seckillStockMap.entrySet()) {
                SkuStockVO skuStockVO = new SkuStockVO();
                skuStockVO.setStock(entry.getValue());
                stockMap.put(entry.getKey(), skuStockVO);
            }
        }

        // 有库存，可以自提的门店id列表
        Set<Long> stationSet = new HashSet<>(stations.size());
        for (Station station : stations) {
            // 判断门店库存是否充足
            if (!checkStationStock(orderStationSpuList, defaultStockPointId, stockMap, station)) {
                continue;
            }
            stationSet.add(station.getStationId());
        }
        return stationSet;
    }


    private static boolean checkStationStock(List<OrderStationProdDto> orderStationSpuList, long defaultStockPointId, Map<String, SkuStockVO> stockMap, Station station) {
        for (OrderStationProdDto orderStationProdDTO : orderStationSpuList) {
            long pointId = defaultStockPointId;
            // 独立仓库并且不是虚拟商品，才能使用门店库存
            if (Objects.equals(station.getStockMode(), StockModeEnum.SINGLE_STOCK.value()) && !Objects.equals(orderStationProdDTO.getSpuMold(), ProdMoldEnum.VIRTUAL.value())) {
                pointId = station.getStationId();
            }
            SkuStockVO skuStockVO = stockMap.get(orderStationProdDTO.getSkuId() + Constant.UNDERLINE + pointId);
            if (Objects.isNull(skuStockVO) || skuStockVO.getStock() < orderStationProdDTO.getCount()) {
                return false;
            }
        }
        return true;
    }

    private static void handleStationOrderInfo(Set<Long> stationSet, List<StationDetailParam> stationList) {
        for (StationDetailParam stationParam : stationList) {
            double distance = 0L;
            if (Objects.nonNull(stationParam.getDistance())) {
                distance = stationParam.getDistance();
            }
            stationParam.setDistance(distance);
//            String timeDate = stationParam.getTimeInfo();
//            StationDetailVO.TimeInfoModeVO timeInfoModeVO = Json.parseObject(timeDate, StationDetailVO.TimeInfoModeVO.class);
//            Long[] shopTime = timeInfoModeVO.getShopTime();
//            String startTime = DateUtil.format(new Date(shopTime[0]), "HH:mm");
//            String endTime = DateUtil.format(new Date(shopTime[1]), "HH:mm");
//            stationParam.setBusiness(startTime + "-" + endTime);
            // 自提门店的库存是否充足
            stationParam.setHasStock(stationSet.contains(stationParam.getStationId()) ? 1 : 0);
        }
    }


    /**
     * 获取上中下午取货时间列表
     * @param startHour  开始时间（小时）
     * @param endHour   结束时间（小时）
     * @param startTime 营业开始时间
     * @param endTime 营业结束时间
     * @return
     */
    private List<String> getBusinessByNoon(int startHour, int endHour,String startTime,String endTime) {
        String morning = "早上";
        String noon = "下午";
        String night = "晚上";
        String zero = "00";
        List<String> hourTime = Lists.newArrayList();
        if (startHour < TWELVE){
            if (endHour > EIGHTEEN){
                hourTime.add(morning + "(" + startTime + "-12:00)");
                hourTime.add(noon + "(12:00-18:00)");
                hourTime.add(night + "(18:00-" + endTime + ")");
            }else if(endHour == EIGHTEEN){
                hourTime.add(morning + "(" + startTime + "-12:00)");
                hourTime.add(noon + "(12:00-18:00)");
                String minute = endTime.split(":")[1];
                if(!zero.equals(minute)){
                    hourTime.add(night + "(18:00-" + endTime + ")");
                }
            }else if (endHour > TWELVE){
                hourTime.add(morning + "(" + startTime + "-12:00)");
                hourTime.add(noon + "(12:00-" + endTime+ ")");
            }else {
                hourTime.add(morning + "(" + startTime + "-" + endTime + ")");
            }
        }else if (startHour >= TWELVE && startHour < EIGHTEEN){
            if (endHour > EIGHTEEN){
                hourTime.add(noon + "(" + startTime + "-18:00)");
                hourTime.add(night + "(18:00-" + endTime + ")");
            }else if(endHour == EIGHTEEN){
                hourTime.add(noon + "(" + startTime + "-18:00)");
                String minute = endTime.split(":")[1];
                if(!zero.equals(minute)){
                    hourTime.add(night + "(18:00-" + endTime + ")");
                }
            }else {
                hourTime.add(night + "(" + startTime + "-" + endTime + ")");
            }
        }else if(startHour >= EIGHTEEN){
            hourTime.add(night + "(" + startTime + "-" + endTime + ")");
        }
        return hourTime;
    }

    private List<String> getBusinessByHour(int startHour, int endHour, int startMinute, int endMinute) {
            String startMinuteStr = "";
        String endMinuteStr = "";
        if (startMinute < TEN){
            startMinuteStr = "0" + startMinute;
        }else {
            startMinuteStr = startMinuteStr + startMinute;
        }
        if (endMinute < TEN){
            endMinuteStr = "0" + endMinute;
        }else {
            endMinuteStr = endMinuteStr + endMinute;
        }

        List<String> hourTime = Lists.newArrayList();
        int hour = startHour;
        if (startHour == endHour){
            hourTime.add(startHour + ":" + startMinuteStr + "-" + endHour + ":"+ endMinuteStr);
        }
        if (startMinute > 0){
            hourTime.add(startHour + ":" + startMinuteStr + "-" + ++hour + ":00");
        }
        while (hour < endHour){
            hourTime.add(hour + ":00-" + ++hour + ":00");
        }
        if (endMinute > 0){
            hourTime.add(hour + ":00-" + hour + ":" + endMinuteStr);
        }
        return hourTime;
    }

    private List<String> getBusinessByHalfHour(int startHour, int endHour, int startMinute, int endMinute) {
        String startMinuteStr = "";
        String endMinuteStr = "";
        if (startMinute < TEN){
            startMinuteStr = "0" + startMinute;
        }else {
            startMinuteStr = startMinuteStr + startMinute;
        }
        if (endMinute < TEN){
            endMinuteStr = "0" + endMinute;
        }else {
            endMinuteStr = endMinuteStr + endMinute;
        }

        List<String> hourTime = Lists.newArrayList();
        int hour = startHour;
        if (startHour == endHour && startMinute < endMinute){
            boolean flag = startMinute < THIRTY && endMinute <= THIRTY;
            if((startMinute >= THIRTY) || flag){
                hourTime.add(startHour + ":" + startMinuteStr + "-" + endHour + ":" + endMinuteStr );
            }else {
                hourTime.add(startHour + ":" + startMinuteStr + "-" + endHour + ":30" );
                hourTime.add(startHour + ":30" + "-" + endHour + ":" + endMinute );
            }
            return hourTime;
        }
        if (startMinute > 0 && startMinute < THIRTY){
            hourTime.add(startHour + ":" + startMinuteStr + "-" + hour + ":30");
            hourTime.add(startHour + ":30-" + ++hour + ":00");
        }else if (startMinute >= THIRTY){
            hourTime.add(startHour + ":"+startMinute+"-" + ++hour + ":00");
        }
        while (hour < endHour){
            hourTime.add(hour + ":00-" + hour + ":30");
            hourTime.add(hour + ":30-" + ++hour + ":00");
        }
        if (endMinute > 0 && endMinute < THIRTY){
            hourTime.add(hour + ":00-" + hour + ":" + endMinuteStr);
        }else if (endMinute >= THIRTY){
            hourTime.add(hour + ":00-" + hour + ":30");
            hourTime.add(hour + ":30-" + hour + ":" + endMinuteStr);
        }
        return hourTime;
    }


    @Override
    public void offline(Station station, String offlineReason, Long sysUserId) {
        // 添加下线处理记录
        Date now = new Date();
        OfflineHandleEvent offlineHandleEvent = new OfflineHandleEvent();
        offlineHandleEvent.setShopId(station.getShopId());
        offlineHandleEvent.setHandleId(station.getStationId());
        offlineHandleEvent.setHandleType(OfflineHandleEventType.STATION.getValue());
        offlineHandleEvent.setOfflineReason(offlineReason);
        offlineHandleEvent.setCreateTime(now);
        offlineHandleEvent.setHandlerId(sysUserId);
        offlineHandleEvent.setStatus(OfflineHandleEventStatus.OFFLINE_BY_PLATFORM.getValue());
        offlineHandleEvent.setUpdateTime(now);
        offlineHandleEventService.save(offlineHandleEvent);

        // 更新活动状态为下线
        stationMapper.updateStatus(station.getStationId(), StationEnum.OFFLINE.getValue());
    }

    @Override
    public void auditSeckill(OfflineHandleEventAuditParam offlineHandleEventAuditParam, Long sysUserId) {
        // 审核通过
        if (Objects.equals(offlineHandleEventAuditParam.getStatus(), OfflineHandleEventStatus.AGREE_BY_PLATFORM.getValue())) {
            // 更新自提点为关闭状态
            stationMapper.updateStatus(offlineHandleEventAuditParam.getHandleId(), StationEnum.INVALID.getValue());
        }
        // 审核不通过
        else if (Objects.equals(offlineHandleEventAuditParam.getStatus(), OfflineHandleEventStatus.DISAGREE_BY_PLATFORM.getValue())) {
            stationMapper.updateStatus(offlineHandleEventAuditParam.getHandleId(), StationEnum.AUDIT_FAIL.getValue());
        }
        // 更新审核时间
        offlineHandleEventService.auditOfflineEvent(offlineHandleEventAuditParam, sysUserId);
    }

    @Override
    @Cacheable(cacheNames = "station", key = "#stationId")
    public Station getStationInfoById(Long stationId) {
        Station stationInfoById = stationMapper.getStationInfoById(stationId);
        return stationInfoById;
    }

    @Override
    public Station getStationInfoByAccount(String account) {
        return stationMapper.getStationInfoByAccount(account);
    }

    @Override
    public List<StationSalesDto> getStationSalesRecord(Long shopId, Long stationId) {
        Date day = DateUtil.beginOfDay(new Date());
        Date month = DateUtil.beginOfMonth(day);
        List<StationSalesDto> stationSalesList = new ArrayList<>();
        StationSalesDto todayStationSalesDto = new StationSalesDto();
        todayStationSalesDto.setSalesType(1);
        StationSalesDto monthStationSalesDto = new StationSalesDto();
        monthStationSalesDto.setSalesType(2);
        double todayPayAmount = 0.0;
        int todayPayOrderNum = 0;
        // 当天支付总计人数
        int todayPayUserNum = 0;
        double monthPayAmount = 0.0;
        int monthPayOrderNum = 0;
        // 当月支付总人数
        int monthPayUserNum = 0;
        // 获取门店端自提的业绩
        List<StationSalesDto> stationSalesDb = stationMapper.getStationSalesRecord(shopId, stationId,day,month);
        Map<Integer, List<StationSalesDto>> stationSaleMap = stationSalesDb.stream().collect(Collectors.groupingBy(StationSalesDto::getSalesType));
        // 获取门店端核销的业绩
        List<StationSalesDto> stationSalesDtos = stationMapper.getStationWriteOffSalesRecord(shopId, stationId,day,month);
        Map<String, List<StationSalesDto>> writeOffSaleMap = stationSalesDtos.stream().collect(Collectors.groupingBy(StationSalesDto::getUserId));
        // 计算支付人数
        for (String userId : writeOffSaleMap.keySet()) {
            monthPayUserNum++;
            for (StationSalesDto stationSalesDto : writeOffSaleMap.get(userId)) {
                if(DateUtil.compare(stationSalesDto.getPayTime(),day) > 0) {
                    todayPayUserNum++;
                    break;
                }
            }
        }
        // 计算支付订单数和收入
        for (StationSalesDto stationSalesDto : stationSalesDtos) {
            // 核销收入计算为: （实付金额 + 平台优惠金额） * 核销数量 / 总数量
            double payAmount = Arith.add(stationSalesDto.getActualTotal(), stationSalesDto.getPlatformAmount());
            payAmount = Arith.div(Arith.mul(payAmount, stationSalesDto.getWriteOffNum()), stationSalesDto.getProductNums(),2);
            if(DateUtil.compare(stationSalesDto.getPayTime(),day) > 0) {
                todayPayAmount = Arith.add(todayPayAmount,payAmount);
                todayPayOrderNum ++;
            }
            monthPayAmount = Arith.add(monthPayAmount,payAmount);
            monthPayOrderNum++;
        }

        // 计算今日支付信息
        List<StationSalesDto> todayStationSalesDb = stationSaleMap.get(1);
        calculationAmountInfo(todayStationSalesDto, todayPayAmount, todayPayOrderNum, todayPayUserNum, writeOffSaleMap, todayStationSalesDb);
        // 计算本月支付信息
        List<StationSalesDto> monthStationSalesDb = stationSaleMap.get(2);
        calculationAmountInfo(monthStationSalesDto, monthPayAmount, monthPayOrderNum, monthPayUserNum, writeOffSaleMap, monthStationSalesDb);
        stationSalesList.add(todayStationSalesDto);
        stationSalesList.add(monthStationSalesDto);
        return stationSalesList;
    }

    /**
     * 计算业绩
     * @param stationSalesDto 返回给前端的业绩
     * @param payAmount 核销支付金额
     * @param payOrderNum 核销支付订单数
     * @param payUserNum 核销支付用户数
     * @param writeOffSaleMap 核销业绩数据
     * @param stationSalesDb 数据库的自提业绩
     */
    private void calculationAmountInfo(StationSalesDto stationSalesDto,  double payAmount, int payOrderNum,
                                       int payUserNum, Map<String, List<StationSalesDto>> writeOffSaleMap, List<StationSalesDto> stationSalesDb) {
        if(CollectionUtil.isEmpty(stationSalesDb)){
            stationSalesDto.setPayAmount(payAmount);
            stationSalesDto.setUserNum(payUserNum);
            stationSalesDto.setPayOrderNumber(payOrderNum);
            stationSalesDto.setCustomerUnitPrice(0.0);
            if (stationSalesDto.getUserNum() != 0) {
                stationSalesDto.setCustomerUnitPrice(Arith.div(stationSalesDto.getPayAmount(), stationSalesDto.getUserNum(), 2));
            }
        }else{
            payUserNum = stationSalesDb.size();
            for (StationSalesDto stationSales : stationSalesDb) {
                payAmount = Arith.add(payAmount,Arith.add(stationSales.getActualTotal(),stationSales.getPlatformAmount()));
                payOrderNum+= stationSales.getPayOrderNumber();
            }
            // 计算人数有无重复
            Map<String, StationSalesDto> salesDtoMap = stationSalesDb.stream().collect(Collectors.toMap(StationSalesDto::getUserId, stationSales -> stationSales));
            for (String userId : writeOffSaleMap.keySet()) {
                if(salesDtoMap.containsKey(userId)){
                    continue;
                }
                payUserNum++;
            }
            stationSalesDto.setPayAmount(payAmount);
            stationSalesDto.setUserNum(payUserNum);
            stationSalesDto.setPayOrderNumber(payOrderNum);
            stationSalesDto.setCustomerUnitPrice(0.0);
            if (stationSalesDto.getUserNum() != 0) {
                stationSalesDto.setCustomerUnitPrice(Arith.div(stationSalesDto.getPayAmount(), stationSalesDto.getUserNum(), 2));
            }
        }
    }

    @Override
    @CacheEvict(cacheNames = "station", key = "#station.stationId")
    public int insertStation(Station station) {
        Long count = stationMapper.selectCount(new LambdaQueryWrapper<Station>()
                .eq(Station::getShopId, station.getShopId())
                .eq(Station::getStationName, station.getStationName())
                .ne(Station::getStatus, -1));
        if (count > 0) {
            throw new YamiShopBindException("自提点名称已存在");
        }
        Date date = new Date();
        station.setStationId(segmentService.getDateFormatSegmentId(SegmentIdKey.STOCK_POINT));
        station.setCreateTime(date);
        station.setUpdateTime(date);
        int insertCount = stationMapper.insert(station);
        // 插入门店仓库
        this.saveStationWarehouse(station);
        return insertCount;
    }

    @Override
    @CacheEvict(cacheNames = "station", key = "#station.stationId")
    public int updateStation(Station station) {
        Long count = stationMapper.selectCount(new LambdaQueryWrapper<Station>()
                .eq(Station::getShopId, station.getShopId())
                .ne(Station::getStationId, station.getStationId())
                .eq(Station::getStationName, station.getStationName())
                .ne(Station::getStatus, -1));
        if (count > 0) {
            throw new YamiShopBindException("自提点名称已存在");
        }
        Station stationDb = stationMapper.selectById(station.getStationId());
        if (!Objects.equals(stationDb.getShopId(), station.getShopId())) {
            throw new YamiShopBindException("当前自提点不属于你的店铺");
        }
        if (!Objects.equals(stationDb.getStatus(), StationStatusEnum.CLOSURE.value()) && !Objects.equals(stationDb.getStatus(), StationStatusEnum.OPEN.value())) {
            // 数据库中自提点的状态不属于关闭或者营业状态时，商家不能直接修改自提点状态
            station.setStatus(stationDb.getStatus());
        }
        if (StrUtil.isNotBlank(station.getPhone()) && PrincipalUtil.isAsteriskMobile(station.getPhone())) {
            if (!PrincipalUtil.isDbPhone(station.getPhone(), stationDb.getPhone(), true)) {
                throw new YamiShopBindException("yami.user.err.phone");
            }
            if (station.getPhone().contains(Constant.ASTERISK)) {
                station.setPhone(stationDb.getPhone());
            }
        }
        station.setUpdateTime(new Date());
        //自提点地址、电话改变，则更新tz_order_self_station表中对应的地址、电话
        String addr =null;
        Boolean addrChange = !stationDb.getProvinceId().equals(station.getProvinceId()) || !stationDb.getCityId().equals(station.getCityId()) ||
                !stationDb.getAreaId().equals(station.getAreaId()) || !StrUtil.equals(stationDb.getAddr(),station.getAddr());
        if(addrChange){
            addr = station.getProvince() + station.getCity() + station.getArea() + station.getAddr();
            stationMapper.changeStationAddr(station.getStationId(),addr, null);

        }
        String phone = null;
        Boolean phoneChange = !StrUtil.equals(stationDb.getPhone(),station.getPhone()) || !StrUtil.equals(stationDb.getPhonePrefix(),station.getPhonePrefix());
        if(phoneChange){
            phone = StrUtil.isNotBlank(station.getPhonePrefix())?station.getPhonePrefix() + "-":"";
            phone = phone + station.getPhone();
        }
        if (addrChange || phoneChange){
            stationMapper.changeStationAddr(station.getStationId(),addr, phone);
        }
        // 更新门店仓库
        this.updateStationWarehouse(station);
        return stationMapper.updateById(station);
    }
    @Override
    @CacheEvict(cacheNames = "station", key = "#station.stationId")
    public void changeAccountInfo(Station station) {
        int count = stationMapper.getCountByAccount(station.getAccount().trim(),station.getStationId());
        if (count > 0){
            // 此账号已存在，请输入新的账号
            throw new YamiShopBindException("yami.station.account.exist");
        }
        Station stationNew = new Station();
        stationNew.setStationId(station.getStationId());
        stationNew.setAccount(station.getAccount());
        stationNew.setPassword(station.getPassword());
        stationMapper.updateById(stationNew);
    }

    @Override
    public int getCountByAccount(String account, Long stationId) {
        return stationMapper.getCountByAccount(account.trim(),stationId);
    }

    @Override
    @CacheEvict(cacheNames = "station", key = "#stationId")
    public int removeStationById(Long stationId) {
        return stationMapper.deleteById(stationId);
    }

    @Override
    @CacheEvict(cacheNames = "station", key = "#stationId")
    public void logicDeleteById(Long stationId) {
        // 判断是否还有库存
        List<StockPointSkuVO> pointSkuList = stockPointSkuService.listByPointId(stationId);
        if (pointSkuList.size() > 0) {
            throw new YamiShopBindException("yami.stock.point.exit");
        }
        // 检查采购订单
        Long unFinishCount = purchaseOrderService.count(new LambdaQueryWrapper<PurchaseOrder>()
                .eq(PurchaseOrder::getWarehouseId, stationId)
                .notIn(PurchaseOrder::getStatus, PurchasesStatusEnum.COMPLETION.value(), PurchasesStatusEnum.VOIDED.value()));
        if (unFinishCount > 0) {
            throw new YamiShopBindException("yami.unfinish.purchase.order.exist");
        }
        // 检查调拨订单
        unFinishCount = allotOrderService.count(new LambdaQueryWrapper<AllotOrder>()
                .and(w -> w.eq(AllotOrder::getOutWarehouseId, stationId)
                        .or().eq(AllotOrder::getInWarehouseId, stationId))
                .notIn(AllotOrder::getStatus, AllotOrderStatusEnum.COMPLETION.getNum(), AllotOrderStatusEnum.VOIDED.getNum()));
        if (unFinishCount > 0) {
            throw new YamiShopBindException("yami.unfinish.allot.order.exist");
        }
        // 检查实物盘点
        unFinishCount = takeStockService.count(new LambdaQueryWrapper<TakeStock>()
                .eq(TakeStock::getWarehouseId, stationId)
                .eq(TakeStock::getBillStatus, TakeStockBillStatusEnum.TAKING.value()));
        if (unFinishCount > 0) {
            throw new YamiShopBindException("yami.unfinish.takestock.exist");
        }
        // 逻辑删除
        this.update(new LambdaUpdateWrapper<Station>()
                .set(Station::getStatus, -1)
                .eq(Station::getStationId, stationId));
    }

    @Override
    @CacheEvict(cacheNames = "station", key = "#stationId")
    public void removeCacheByStationId(Long stationId) {

    }

    @Override
    public void switchStationStockMode(Long stationId, Integer type, Long shopId, Long employeeId) {
        Integer stockMode;
        Station station = new Station();
        station.setStationId(stationId);
        if (Objects.nonNull(type)) {
            stockMode = StockModeEnum.ALL_STOCK.value();
        } else {
            stockMode = StockModeEnum.SINGLE_STOCK.value();
        }
        station.setStockMode(stockMode);
        stationMapper.updateById(station);
        // 更新库存
        skuStockService.updateStockMode(stationId, stockMode, type, shopId, employeeId);
        // 切换成共享库存时，需作废调拨订单，采购订单和实物盘点
        if (Objects.equals(stockMode, StockModeEnum.ALL_STOCK.value())) {
            WarehouseDTO warehouseSearchDTO = new WarehouseDTO();
            warehouseSearchDTO.setShopId(stationId);
            warehouseSearchDTO.setSysType(SysTypeEnum.STATION.value());
            List<WarehouseVO> warehouseVOS = warehouseService.listWarehouse(warehouseSearchDTO);
            if (CollectionUtils.isEmpty(warehouseVOS)) {
                return;
            }
            Long warehouseId = warehouseVOS.get(0).getWarehouseId();
            // 作废调拨
            allotOrderService.nullifyOrderByWarehouseId(warehouseId);
            // 作废采购
            purchaseOrderService.nullifyByWarehouseId(warehouseId);
            // 作废实物盘点
            takeStockService.nullifyByWarehouseId(warehouseId);
        }
    }

    @Override
    public OrderSelfStationDto getOrderStation(UserDeliveryInfoVO userDeliveryInfoVO, ArrayList<OrderStationProdDto> orderStationSpuList) {
        Long defaultPointId = orderStationSpuList.get(0).getDefaultStockPointId();
        OrderStationDto orderStationDTO = new OrderStationDto();
        orderStationDTO.setStationId(userDeliveryInfoVO.getStationId());
        OrderSelfStationDto orderSelfStation = userDeliveryInfoVO.getOrderSelfStation();
        orderStationDTO.setLat(orderSelfStation.getLat());
        orderStationDTO.setLng(orderSelfStation.getLng());
        orderStationDTO.setShopId(userDeliveryInfoVO.getDvyTypes().get(0).getShopId());
        orderStationDTO.setSeckillId(userDeliveryInfoVO.getSeckillId());

        // 要判断门店是否有库存，所以先查询所有的门店列表
        List<Station> shopStationList = stationMapper.listSimpleStation(orderStationDTO.getShopId(), StatusEnum.ENABLE.value());
        // 没有门店，直接返回null
        if (CollUtil.isEmpty(shopStationList)) {
            // 没有门店列表
            orderSelfStation.setStationStockStatus(StationStockStatus.NOT_STATION_LIST.getStatus());
            return orderSelfStation;
        }
        Set<Long> stationSet = stationStockSet(orderStationSpuList, shopStationList, orderStationDTO, defaultPointId);


        // 有门店，但所有门店的库存数量都不足时，返回一个状态为库存不足的门店，代表当前区域库存不足
        if (CollUtil.isEmpty(stationSet)) {
            // 门店没有库存
            orderSelfStation.setStationStockStatus(StationStockStatus.NOT_STOCK.getStatus());
            return orderSelfStation;
        }
        // 存在库存充足的门店
        orderStationDTO.setStationIds(new ArrayList<>(stationSet));
        Page<StationDetailParam> page = new PageParam<>();
        page.setSize(1);
        page.setPages(1);
        IPage<StationDetailParam> stationIpage = stationMapper.getStationList(page,orderStationDTO);
        if (CollUtil.isEmpty(stationIpage.getRecords())) {
            // 门店没有库存
            orderSelfStation.setStationStockStatus(StationStockStatus.NOT_STOCK.getStatus());
            return orderSelfStation;
        }
        StationDetailParam stationDetailVO = stationIpage.getRecords().get(0);
        orderSelfStation.setStationId(stationDetailVO.getStationId());
        orderSelfStation.setStationName(stationDetailVO.getStationName());
        orderSelfStation.setPic(stationDetailVO.getPic());
        return orderSelfStation;
    }

    /**
     * 创建门店仓库
     * @param station 门店
     */
    private void saveStationWarehouse(Station station) {
        WarehouseDTO warehouseDTO = this.buildWarehouseDTO(station);
        // warehouseId和stationId一样
        warehouseDTO.setWarehouseId(station.getStationId());
        warehouseService.insertWarehouseAndArea(warehouseDTO);
    }

    /**
     * 更新门店仓库
     * @param station 门店
     */
    private void updateStationWarehouse(Station station) {
        Station dbStation = stationMapper.getStationInfoById(station.getStationId());
        // "门店名称"或"地址"或"联系电话"更改后才更新仓库数据
        boolean isUpdate = !Objects.equals(dbStation.getStationName(), station.getStationName())
                || !Objects.equals(dbStation.getAreaId(), station.getAreaId())
                || !Objects.equals(dbStation.getPhone(), station.getPhone());
        if (!isUpdate) {
            return;
        }
        if (Objects.nonNull(station.getPhone()) && !PrincipalUtil.isDbPhone(station.getPhone(), dbStation.getPhone(), false)) {
            throw new YamiShopBindException("请输入正确的手机号");
        }
        if (Objects.isNull(station.getPhone()) || station.getPhone().contains(Constant.ASTERISK)) {
            station.setPhone(dbStation.getPhone());
        }
        WarehouseDTO warehouseDTO = new WarehouseDTO();
        warehouseDTO.setShopId(station.getStationId());
        warehouseDTO.setSysType(SysTypeEnum.STATION.value());
        List<WarehouseVO> warehouses = warehouseService.listWarehouse(warehouseDTO);
        if (CollectionUtils.isEmpty(warehouses)) {
            this.saveStationWarehouse(station);
            return;
        }
        warehouseDTO = this.buildWarehouseDTO(station);
        warehouseDTO.setWarehouseId(warehouses.get(0).getWarehouseId());
        warehouseService.updateWarehouseAndArea(warehouseDTO);
    }

    /**
     * 删除门店仓库
     * @param stationId 门店id
     */
    private void deleteStationWarehouse(Long stationId) {
        WarehouseDTO warehouseDTO = new WarehouseDTO();
        warehouseDTO.setShopId(stationId);
        warehouseDTO.setSysType(SysTypeEnum.STATION.value());
        List<WarehouseVO> warehouses = warehouseService.listWarehouse(warehouseDTO);
        if (!CollectionUtils.isEmpty(warehouses)) {
            warehouseService.deleteWarehouseAndArea(warehouses.get(0).getWarehouseId());
        }
    }

    /**
     * 构建仓库DTO
     * @param station 门店
     * @return 仓库dto
     */
    private WarehouseDTO buildWarehouseDTO(Station station) {
        WarehouseDTO warehouseDTO = new WarehouseDTO();
        BeanUtils.copyProperties(station, warehouseDTO);
        warehouseDTO.setShopId(station.getStationId());
        warehouseDTO.setSysType(SysTypeEnum.STATION.value());
        warehouseDTO.setWarehouseName(station.getStationName());
        warehouseDTO.setType(1);
        warehouseDTO.setPhone(station.getPhone());
        warehouseDTO.setAddress(station.getAddr());
        List<AreaDto> areas = new ArrayList<>(1);
        AreaDto areaDto = new AreaDto();
        areaDto.setAreaId(station.getAreaId());
        areas.add(areaDto);
        warehouseDTO.setCityList(areas);
        return warehouseDTO;
    }
}
